#pragma once
#include <unordered_map>
#include "util.hpp"
#include "config.hpp"
#include <pthread.h>

namespace cloud
{
    struct BackupInfo
    {
        BackupInfo() = default;
        BackupInfo(const std::string &path) 
        {
            UtilFile root(path);
            pack_flag = false;
            mtime = root.lastModtime();
            atime = root.lastAcctime();
            fsize = root.fileSize();
            real_path = path;
            // ./backdir/test.txt --> /download/test.txt
            url = Config::getInstance().getDownloadPrefix() + root.fileName();
            // ./backdir/test.txt --> ./packdir/test.txt.lz
            pack_path = Config::getInstance().getPackDir() + root.fileName() + Config::getInstance().getPackfileSuffix();
        }

        bool pack_flag;
        time_t mtime;
        time_t atime;
        size_t fsize;
        std::string url;
        std::string real_path;
        std::string pack_path;
    };

    class DataManager // 为什么不用单例模式管理
    {
    public:
        DataManager()
        {
            _backup_file = Config::getInstance().getBackupFile();
            pthread_rwlock_init(&_rwlock, nullptr);
            initLoad();
        }

        void _update(const BackupInfo &info)
        {
            pthread_rwlock_wrlock(&_rwlock);
            _table[info.url] = info;
            pthread_rwlock_unlock(&_rwlock);

            storage();
        }

        void insert(const BackupInfo &info)
        {
            _update(info);
        }

        void update(const BackupInfo &info) // 覆盖式修改
        {
            _update(info);
        }

        bool getOneByUrl(const std::string &url, BackupInfo *infos)
        {
            pthread_rwlock_rdlock(&_rwlock);
            auto result = _table.find(url);
            pthread_rwlock_unlock(&_rwlock);

            if(result == _table.end())
            {
                
                infos = nullptr;
                return false;
            }
            *infos = result->second;

            return true;
        }

        bool getOneByReal(const std::string &path, BackupInfo *info)
        {
            pthread_rwlock_rdlock(&_rwlock);
            auto it = _table.begin();
            while(it != _table.end())
            {
                if(it->second.real_path == path)
                    break;
                it++;
            }
            pthread_rwlock_unlock(&_rwlock);

            if(it == _table.end())
            {
                info = nullptr;
                return false;
            }
            *info = it->second;

            return true;
        }

        void getAll(std::vector<BackupInfo> *arry)
        {
            pthread_rwlock_rdlock(&_rwlock);
            for(auto it : _table)
            {
                arry->push_back(it.second);
            }
            pthread_rwlock_unlock(&_rwlock);
        }

        ~DataManager()
        {
            pthread_rwlock_destroy(&_rwlock);
        }
    private:
        // 每次修改数据都要持久化一次 单个数据持久化 追加写
        void storage()
        {
            std::vector<BackupInfo> infos;
            getAll(&infos);
            Json::Value root;

            for(auto &info: infos)
            {
                Json::Value item;
                item["pack_flag"] = info.pack_flag;
                item["mtime"] = static_cast<Json::UInt>(info.mtime);
                item["atime"] = static_cast<Json::UInt>(info.atime);
                item["fsize"] = static_cast<Json::UInt>(info.fsize);
                item["url"] = info.url;
                item["real_path"] = info.real_path;
                item["pack_path"] = info.pack_path;
                root.append(item);
            }
            std::string body;
            JosnUtil::serialize(root, body);

            UtilFile backfile(_backup_file);
            backfile.setContent(body);
        }

        bool initLoad()
        {
            // 存在性判断
            UtilFile backfile(_backup_file);
            if(backfile.exists() == false)
                return false;
            // 读取数据
            std::string body;
            backfile.getContent(body);
            // 将数据反序列化
            Json::Value root;
            JosnUtil::unserialize(body, root);
            for(int i = 0; i < root.size(); i++)
            {
                BackupInfo info;
                info.pack_flag = root[i]["pack_flag"].asBool();
                info.fsize = root[i]["fsize"].asUInt();
                info.atime = root[i]["atime"].asUInt();
                info.mtime = root[i]["mtime"].asUInt();
                info.url = root[i]["url"].asString();
                info.real_path = root[i]["real_path"].asString();
                info.pack_path = root[i]["pack_path"].asString();
                insert(info);
            }

            return true;
        }
    private:
        std::string _backup_file; // 持久化存储文件
        pthread_rwlock_t _rwlock; // 读写锁
        std::unordered_map<std::string, BackupInfo> _table; // <url, BackupInfo> 数据在内存中以hash表存储
    };
}